﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Nodes;

namespace DotNetCommon.Extensions;

/// <summary>
/// JsonObject、JsonArray 扩展类
/// </summary>
public static class JsonExtensions
{
    #region JsonArray ContainsObject/ContainsObjectAny/ContainsObjectAll
    /// <summary>
    /// 当前集合(<c>jsonArray</c>)是否含有<c>value</c>
    /// <list type="bullet">
    /// <item>当<c>jsonArray</c>为空时,直接返回false,否则下一步;</item>
    /// <item>返回<c>jsonArray</c>是否含有<c>value</c>;</item>
    /// </list>
    /// 示例:
    /// <code>
    /// new[] { 1, 2, 3 }.ToJsonArray().ContainsObject(1, EqualityComparer&lt;int>.Default).ShouldBe(true);
    /// </code>
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>比较前会将<c>JsonArray</c>反序列化为List&lt;T></item>
    /// </list>
    /// </remarks>
    public static bool ContainsObject<T>(this JsonArray jsonArray, T value)
        => ContainsObject(jsonArray, value, null);

    /// <inheritdoc cref="ContainsObject{T}(JsonArray, T)"/>
    public static bool ContainsObject<T>(this JsonArray jsonArray, T value, IEqualityComparer<T> equalityComparer = null)
    {
        if (jsonArray == null || jsonArray.Count == 0) return false;
        var seq = jsonArray.ToJsonString().ToObject<List<T>>();
        return seq.Contains(value, equalityComparer);
    }

    /// <summary>
    /// 当前集合(<c>jsonArray</c>)是否含有<c>values</c>中的任何一个
    /// <list type="bullet">
    /// <item>当<c>objects</c>为空时,直接返回true,否则下一步;</item>
    /// <item>当<c>jsonArray</c>为空时,直接返回false,否则下一步;</item>
    /// <item>返回<c>jsonArray</c>和<c>objects</c>是否有交叉(Intersect);</item>
    /// </list>
    /// 示例:
    /// <code>
    /// new[] { 1, 2, 3 }.ToJsonArray().ContainsObjectAny(new[] { 1, 5 }).ShouldBe(true);
    /// </code>
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>比较前会将<c>JsonArray</c>反序列化为List&lt;T></item>
    /// </list>
    /// </remarks>
    public static bool ContainsObjectAny<T>(this JsonArray jsonArray, IEnumerable<T> objects)
        => ContainsObjectAny<T>(jsonArray, objects, null);

    /// <inheritdoc cref="ContainsObjectAny{T}(JsonArray, IEnumerable{T})"/>
    public static bool ContainsObjectAny<T>(this JsonArray jsonArray, IEnumerable<T> objects, IEqualityComparer<T> equalityComparer = null)
    {
        if (objects.IsNullOrEmpty()) return true;
        if (jsonArray == null || jsonArray.Count == 0) return false;
        var seq = jsonArray.ToJsonString().ToObject<List<T>>();
        return seq.ContainsAny(objects, equalityComparer);
    }

    /// <summary>
    /// 当前集合(<c>jsonArray</c>)是否包含<c>objects</c>中的全部
    /// <list type="bullet">
    /// <item>当<c>objects</c>为空时,直接返回true,否则下一步;</item>
    /// <item>当<c>jsonArray</c>为空时,直接返回false,否则下一步;</item>
    /// <item>返回<c>objects</c>减去<c>jsonArray</c>后是否为空(Except);</item>
    /// </list>
    /// 示例:
    /// <code>
    /// new[] { 1, 2, 3 }.ToJsonArray().ContainsObjectAll(new[] { 1, 2 }).ShouldBe(true);
    /// </code>
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>比较前会将<c>JsonArray</c>反序列化为List&lt;T></item>
    /// </list>
    /// </remarks>
    public static bool ContainsObjectAll<T>(this JsonArray jsonArray, IEnumerable<T> objects)
        => ContainsObjectAll<T>(jsonArray, objects, null);

    /// <inheritdoc cref="ContainsObjectAll{T}(JsonArray, IEnumerable{T})"/>
    public static bool ContainsObjectAll<T>(this JsonArray jsonArray, IEnumerable<T> objects, IEqualityComparer<T> equalityComparer = null)
    {
        if (objects.IsNullOrEmpty()) return true;
        if (jsonArray == null || jsonArray.Count == 0) return false;
        var seq = jsonArray.ToJsonString().ToObject<List<T>>();
        return seq.ContainsAll(objects, equalityComparer);
    }
    #endregion

    #region JsonArray AddFluent/AddRangeFluent/ClearFluent/InsertAtFluent/RemoveAtFluent/RemoveFluent/SetFluent
    /// <summary>
    /// 向集合<c>jsonArray</c>中添加项<c>item</c>并返回自身
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>jsonArray为null时抛出异常</item>
    /// </list>
    /// </remarks>
    public static JsonArray AddFluent(this JsonArray jsonArray, JsonNode item)
    {
        AssertUtil.NotNull(jsonArray);
        jsonArray.Add(item);
        return jsonArray;
    }

    /// <summary>
    /// 向集合<c>jsonArray</c>中添加项集合<c>items</c>并返回自身
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>jsonArray为null时抛出异常</item>
    /// <item>items为null时, 则忽略添加</item>
    /// </list>
    /// </remarks>
    public static JsonArray AddRangeFluent<T>(this JsonArray jsonArray, IEnumerable<T> items)
    {
        AssertUtil.NotNull(jsonArray);
        if (items.IsNullOrEmpty()) return jsonArray;
        foreach (var item in items) jsonArray.Add(item);
        return jsonArray;
    }

    /// <summary>
    /// 清空集合<c>jsonArray</c>并返回自身
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>jsonArray为null时抛出异常</item>
    /// </list>
    /// </remarks>
    public static JsonArray ClearFluent(this JsonArray jsonArray)
    {
        AssertUtil.NotNull(jsonArray);
        jsonArray.Clear();
        return jsonArray;
    }

    /// <summary>
    /// 向集合<c>jsonArray</c>中指定位置插入向<c>item</c>并返回自身
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>jsonArray为null时抛出异常</item>
    /// </list>
    /// </remarks>
    public static JsonArray InsertAtFluent(this JsonArray jsonArray, int index, JsonNode item)
    {
        AssertUtil.NotNull(jsonArray);
        jsonArray.Insert(index, item);
        return jsonArray;
    }

    /// <summary>
    /// 从集合<c>jsonArray</c>中移除指定位置的项,并返回自身
    /// </summary>
    /// <remarks>
    /// 注意: 
    /// <list type="bullet">
    /// <item>jsonArray为null时抛出异常</item>
    /// </list>
    /// </remarks>
    public static JsonArray RemoveAtFluent(this JsonArray jsonArray, int index)
    {
        AssertUtil.NotNull(jsonArray);
        jsonArray.RemoveAt(index);
        return jsonArray;
    }

    /// <summary>
    /// 从集合<c>jsonArray</c>中移除符合条件的项,并返回自身
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果集合为null,抛出异常</item>
    /// <item>如果match为null,抛出异常</item>
    /// </list>
    /// </remarks>
    public static JsonArray RemoveFluent(this JsonArray jsonArray, Predicate<JsonNode> match)
    {
        AssertUtil.NotNull(jsonArray);
        AssertUtil.NotNull(match);
        for (var i = 0; i < jsonArray.Count; i++)
        {
            if (match(jsonArray[i]))
            {
                jsonArray.RemoveAt(i);
                i--;
            }
        }
        return jsonArray;
    }

    /// <summary>
    /// Fluent风格: 设置集合中指定索引的值
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果集合为null或索引超出,抛出异常</item>
    /// </list>
    /// </remarks>
    public static JsonArray SetFluent(this JsonArray jsonArray, int index, JsonNode b)
    {
        AssertUtil.NotNull(jsonArray);
        jsonArray[index] = b;
        return jsonArray;
    }

    /// <summary>
    /// Fluent风格: 设置集合中指定索引的值
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果集合为null或索引超出,抛出异常</item>
    /// <item>如果func为null,则不做任何修改</item>
    /// </list>
    /// </remarks>
    public static JsonArray SetUpdateFluent(this JsonArray jsonArray, int index, Func<JsonNode, JsonNode> func)
    {
        AssertUtil.NotNull(jsonArray);
        if (func == null) return jsonArray;
        jsonArray[index] = func(jsonArray[index]);
        return jsonArray;
    }

    /// <summary>
    /// Fluent风格: 批量设置集合中的值
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果集合为null,抛出异常</item>
    /// <item>如果filter为null,抛出异常</item>
    /// <item>如果func为null,则不做任何修改</item>
    /// </list>
    /// </remarks>
    public static JsonArray SetUpdateFluent(this JsonArray jsonArray, Func<JsonNode, bool> filter, Func<JsonNode, JsonNode> func)
    {
        AssertUtil.NotNull(jsonArray);
        AssertUtil.NotNull(filter);
        if (func == null) return jsonArray;
        for (int i = 0; i < jsonArray.Count; i++)
        {
            var b = filter?.Invoke(jsonArray[i]);
            if (b == false) continue;
            jsonArray[i] = func(jsonArray[i]);
        }
        return jsonArray;
    }
    #endregion

    #region JsonObject SetFluent/SetBatchFluent/RemoveFluent/ClearFluent
    /// <summary>
    /// 给<c>jsonObject</c>设置属性值, 并返回自身
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果jsonObject为null,抛出异常</item>
    /// </list>
    /// </remarks>
    public static JsonObject SetFluent(this JsonObject jsonObject, string key, JsonNode value)
    {
        AssertUtil.NotNull(jsonObject);
        jsonObject[key] = value;
        return jsonObject;
    }

    /// <summary>
    /// 给<c>jsonObject</c>设置属性值, 并返回自身
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果jsonObject为null,抛出异常</item>
    /// <item>如果func为null,则忽略更改</item>
    /// </list>
    /// </remarks>
    public static JsonObject SetUpdateFluent(this JsonObject jsonObject, string key, Func<JsonNode, JsonNode> func)
    {
        AssertUtil.NotNull(jsonObject);
        if (func == null) return jsonObject;
        jsonObject[key] = func(jsonObject[key]);
        return jsonObject;
    }

    /// <summary>
    /// 移除<c>jsonObject</c>中的某个属性
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果jsonObject为null,抛出异常</item>
    /// </list>
    /// </remarks>
    public static JsonObject RemoveFluent(this JsonObject jsonObject, string key)
    {
        AssertUtil.NotNull(jsonObject);
        jsonObject.Remove(key);
        return jsonObject;
    }

    /// <summary>
    /// 清空<c>jsonObject</c>中的属性
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果jsonObject为null,抛出异常</item>
    /// </list>
    /// </remarks>
    public static JsonObject ClearFluent(this JsonObject jsonObject)
    {
        AssertUtil.NotNull(jsonObject);
        jsonObject.Clear();
        return jsonObject;
    }
    #endregion

    #region JsonArray FindIndex/FindLastIndex
    /// <summary>
    /// 类似 List.FindIndex()
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果集合为null,抛出异常</item>
    /// <item>如果match为null,抛出异常</item>
    /// </list>
    /// </remarks>
    public static int FindIndex(this JsonArray jsonArray, Predicate<JsonNode> match)
    {
        AssertUtil.NotNull(jsonArray);
        AssertUtil.NotNull(match);
        for (int i = 0; i < jsonArray.Count; i++)
        {
            if (match(jsonArray[i])) return i;
        }
        return -1;
    }

    /// <summary>
    /// 类似 List.FindLastIndex()
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果集合为null,抛出异常</item>
    /// <item>如果match为null,抛出异常</item>
    /// </list>
    /// </remarks>
    public static int FindLastIndex(this JsonArray jsonArray, Predicate<JsonNode> match)
    {
        AssertUtil.NotNull(jsonArray);
        AssertUtil.NotNull(match);
        for (int i = jsonArray.Count - 1; i >= 0; i--)
        {
            if (match(jsonArray[i])) return i;
        }
        return -1;
    }
    #endregion
}
